#include"http_conn.h"
#include"setfd.h"
#include"memorypool.h"

#include<map>
// #include<sys/time.h>
// #include<unistd.h>

const char* ok_200_title="OK";
const char* error_400_title="Bad Request";
const char* error_400_form="Your request has bad syntax or is inherently impossible to staisfy.\n";
const char* error_403_title="Forbidden";
const char* error_403_form="You do not have permission to get file form this server.\n";
const char* error_404_title="Not Found";
const char* error_404_form="The requested file was not found on this server.\n";
const char* error_500_title="Internal Error";
const char* error_500_form="There was an unusual problem serving the request file.\n";
const char* doc_root="./http";

//extern char* selectmysql(char* s);
extern int setnonblocking(int fd);
extern void addfd(int epollfd,int fd,bool one_shot);
extern void removefd(int epollfd,int fd);
extern void modfd(int epollfd,int fd,int ev,bool lis);

extern std::map<std::string, file_info*> filehead;
extern memorypool* MemPool;

int http_conn::m_user_count=0;
int http_conn::m_epollfd=-1;
//int sio = 0;

//关闭连接
void http_conn::close_conn(bool real_close)
{
    if (real_close && (m_sockfd != -1))
    {
        removefd(m_epollfd,m_sockfd);
        m_sockfd=-1;
        m_user_count--;
    }
}

//htt_conn对象的主初始化函数
void http_conn::init(int sockfd,const sockaddr_in &addr)
{
    m_sockfd=sockfd;
    m_address=addr;
    addfd(m_epollfd,sockfd,true);
    m_user_count++;
    int reuse=1;
    time_t cur=time(NULL);
    time_out=cur+15;
    te=nullptr;
    init();
}

//htt_conn从初始化函数
void http_conn::init()
{
    m_check_state=CHECK_STATE_REQUESTLINE;
    m_linger=false;
    user_status=LONGIN;
    m_method=GET;
    m_url=0;
    m_version=0;
    m_content_length=0;
    m_host=0;
    user_name=0;
    user_pwd=0;
    m_start_line=0;
    m_checked_idx=0;

    m_read_idx=0;
    m_write_idx=0;
    
    memoryblock = 0;
    //memset(m_read_buf,'\0',READ_BUFFER_SIZE);
    m_read_buf = nullptr;
    m_write_buf = nullptr;
    //memset(m_write_buf,'\0',WRITE_BUFFER_SIZE);
    memset(m_real_file,'\0',FILENAME_LEN);
}

//提取报文中的一行
http_conn::LINE_STATUS http_conn::parse_line()
{
    char temp;
    for (; m_checked_idx < m_read_idx; ++m_checked_idx)
    {
        temp=m_read_buf[m_checked_idx];
        if (temp=='\r')
        {
            if ((m_checked_idx+1)==m_read_idx)
            {
                return LINE_OPEN;
            }
            else if (m_read_buf[m_checked_idx+1]=='\n')
            {
                m_read_buf[m_checked_idx++]='\0';
                m_read_buf[m_checked_idx++]='\0';
                return LINE_OK;
            }
            return LINE_BAD;
        }
        else if (temp=='\n')
        {
            if (m_checked_idx>=1 && m_read_buf[m_checked_idx - 1]=='\r')
            {
                m_read_buf[m_checked_idx-1]='\0';
                m_read_buf[m_checked_idx++]='\0';
                return LINE_OK;
            }
            return LINE_BAD;
        }
    }
    return LINE_OPEN;
}

//循环读取缓冲区，直到读完
bool http_conn::read()
{
    int bytes_read=0;
    int bytes=0;
    char* nums[10];
    while (true)
    {
        char* tmp = static_cast<char*>(MemPool->task(512));
        // sio++;
        // printf("%d\n", sio);
        nums[memoryblock++] = tmp;
        bytes_read = recv(m_sockfd, tmp, 512, 0);
        //printf("%s\n",tmp);
        bytes += bytes_read;
        if(bytes_read == -1)
        {
            bytes++;
            if (errno==EAGAIN||errno==EWOULDBLOCK)
            {
                if(--memoryblock == 1)
                {
                    m_read_buf = nums[0];
                }
                else
                {
                    tmp = static_cast<char*>(MemPool->task(memoryblock * 512));
                    // sio++;
                    // printf("%d\n", sio);
                    for(int i = 0; i < memoryblock;i++)
                    {
                        if(i == memoryblock-1)
                            strncpy(tmp, nums[i], bytes - i * 512);
                        else
                            strncpy(tmp, nums[i], 512);
                        MemPool->push(static_cast<void*>(nums[i]), 512);
                        // sio--;
                        // printf("%d\n", sio);
                    }
                    m_read_buf = tmp;
                }
                MemPool->push(static_cast<void*>(nums[memoryblock]), 512);
                // sio--;
                // printf("%d\n", sio);
                m_read_idx+=bytes;
                break;
            }
            return false;
        }
        if(bytes_read == 0)
            return false;

    }
    return true;
}

//分析HTTP请求行
http_conn::HTTP_CODE http_conn::parse_request_line(char* text)
{
    m_url=strpbrk(text," \t");
    if (!m_url)
    {
        return BAD_REQUEST;
    }
    *m_url++='\0';
    char* method=text;
    if (strcasecmp(method,"GET")==0)
    {
        m_method=GET;
    }
    else
    {
        return BAD_REQUEST;
    }
    m_url+=strspn(m_url," \t");
    m_version=strpbrk(m_url," \t");
    user_name=strchr(m_url,'u');
    if (!m_version)
    {
        return BAD_REQUEST;
    }
   *m_version++='\0';
    m_version+=strspn(m_version," \t");
    if(user_name)
    {
        user_name+=5;
        if(user_pwd=strchr(user_name,'&'))
        {
            *user_pwd++='\0';
            user_pwd+=9;
        }
        else
        {
            user_name=NULL;  
        }
    }
    if (strcasecmp(m_version,"HTTP/1.1") != 0)
    {
        return BAD_REQUEST;
    }
    if ((strncasecmp(m_url,"/http",5)==0)&&!user_name&&!user_pwd)
    {
        m_url+=5;
        m_url=strchr(m_url,'/');
    }

    if (!m_url||m_url[0] != '/')
    {
        return BAD_REQUEST;
    }
    m_check_state=CHECK_STATE_HEADER;
    return NO_REQUEST;
}

//解析http请求的一个头部信息
http_conn::HTTP_CODE http_conn::parse_headers(char* text)
{
    if (text[0]=='\0')
    {
        if (m_content_length != 0)
        {
            m_check_state=CHECK_STATE_CONTENT;
            return NO_REQUEST;
        }
        return GET_REQUEST;
    }
    else if (strncasecmp(text,"Connection:",11)==0)
    {
        text+=11;
        text+=strspn(text," \t");
        if (strcasecmp(text,"keep-alive")==0)
        {
            m_linger=true;
        }
    }
    else if (strncasecmp(text,"Content-length:",15)==0)
    {
        text+=15;
        text+=strspn(text," \t");
        m_content_length=atol(text);
    }
    else if ((strncasecmp(text,"Referer:",8)==0)&&user_name)
    {
        text+=8;
        text+=strspn(text," \t");
        char* stais=strchr(text,'p');
        *stais++='\0';
        stais=strchr(stais,'p');
        stais+=2;
        if(strcasecmp(stais,"index.html")==0)
        {
            user_status=LONGIN;
        }
        else if(strcasecmp(stais,"registered.html")==0)
        {
            user_status=REGISTERED;
        }
        else if(strcasecmp(stais,"reset.html")==0)
        {
            user_status=RESET;
        }
    }
    else if (strncasecmp(text,"Host:",5)==0)
    {
        text+=5;
        text+=strspn(text," \t");
        m_host=text;
    }
    return NO_REQUEST;
}

//分析报文段主信息，实际上并未分析
http_conn::HTTP_CODE http_conn::parse_content(char* text)
{
    if (m_read_idx>=(m_content_length+m_checked_idx))
    {
        text[m_content_length]='\0'; 
        return GET_REQUEST;
    }
    return NO_REQUEST;
}

//线程调用的分析HTTP报文的主函数
http_conn::HTTP_CODE http_conn::process_read()
{
    LINE_STATUS line_status=LINE_OK;
    HTTP_CODE ret=NO_REQUEST;
    char* text=0;

    while (((m_check_state==CHECK_STATE_CONTENT) && (line_status==LINE_OK))||((line_status=parse_line())==LINE_OK))
    {
        text=get_line();
        m_start_line=m_checked_idx;
        //printf("%s\n",text);
        switch (m_check_state)
        {
            case CHECK_STATE_REQUESTLINE:
            {
                ret=parse_request_line(text);
                if (ret==BAD_REQUEST)
                {
                    return BAD_REQUEST;
                }
                break;
            }
            case CHECK_STATE_HEADER:
            {
                ret=parse_headers(text);
                if (ret==BAD_REQUEST)
                {
                    return BAD_REQUEST;
                }
                else if (ret==GET_REQUEST)
                {
                    return do_request();
                }
                break;
            }
            case CHECK_STATE_CONTENT:
            {
                ret=parse_content(text);
                if (ret==GET_REQUEST)
                {
                    return do_request(); 
                }
                line_status=LINE_OPEN;  
                break;
            }
            default:
            {
                return INTERNAL_ERROR;
            }
        }
    }
    return NO_REQUEST;
}

//线程根据调用分析报文主函数的结果，采取相应的答复处理
http_conn::HTTP_CODE http_conn::do_request()
{
    if(user_name&&user_pwd)
    {
        char s_sel[1024];
        char* sl=NULL;
        memset(s_sel,'/0',1024);
        switch(user_status)
        {
            case LONGIN:
            {
                // sprintf(s_sel,"select pwd from user_info where name=\'%s\'",user_name);
                // sl=selectmysql(s_sel);
                // if(s_sel&&strcasecmp(sl,user_pwd)==0)
                // {
                user_status=HAVE_LONGIN;
                m_url="/myweb/index.html";
                // }
                // else
                // {
                //     user_status=PWDERRON;
                //     m_url="/pwderron.html";
                // }
                break;
            }
            case REGISTERED:
            {
                sprintf(s_sel,"select name from user_info where name=\'%s\'",user_name);
                if(sl&&strcasecmp(sl,user_name)==0)
                {
                    user_status=RENAME;
                    m_url="/rename.html";
                }
                else
                {
                    memset(s_sel,'/0',1024);
                    sl=NULL;
                    sprintf(s_sel,"insert into user_info values(\'%s\',\'%s\')",user_name,user_pwd);
                    m_url="/index.html";
                }
                break;
            }
        }
    }
    strcpy(m_real_file,doc_root);
    int len=strlen(doc_root);
    strncpy(m_real_file+len,m_url,FILENAME_LEN-len-1);
    
    MemPool->push(static_cast<void*>(m_read_buf), memoryblock * 512);
    // sio--;
    // printf("%d\n", sio);
    memoryblock = 0;
    m_read_idx = 0;
    m_read_buf = nullptr;
    // if(stat(m_real_file,&m_file_stat))
    // {
    //     return NO_RESOURCE;
    // }
    // if(!(m_file_stat.st_mode&S_IROTH))
    // {
    //     return FORBIDDEN_REQUEST;
    // }
    // if(S_ISDIR(m_file_stat.st_mode))
    // {
    //     return BAD_REQUEST;
    // }

    this->te=filehead[std::string(m_real_file)];
    if(!te)
        return NO_RESOURCE;
    return FILE_REQUEST;
}


//IO主线程调用向连接的fd发送准备好的数据
bool http_conn::write()
{
    int temp=0;
    int bytes_have_send=0;
    int bytes_to_send=m_write_idx;
    if (bytes_to_send==0)
    {
        modfd(m_epollfd,m_sockfd,EPOLLIN,true);
        init();
        return true;
    }

    while (1)
    {
        temp=writev(m_sockfd,m_iv,m_iv_count);
        if (temp<-1)
        {
            if (errno==EAGAIN)
            {
                modfd(m_epollfd,m_sockfd,EPOLLOUT,true);
                return true;
            }
            return false;
        }

        bytes_to_send -= temp;
        bytes_have_send+=temp;
        
        if (bytes_to_send<=bytes_have_send)
        {
            MemPool->push(static_cast<void*>(m_write_buf), memoryblock * 512);
            // sio--;
            // printf("%d\n", sio);
            memoryblock = 0;
            m_write_idx = 0;
            m_write_buf = nullptr;
            if (m_linger)
            {
                init();
                modfd(m_epollfd,m_sockfd,EPOLLIN,true);
                return true;
            }
            else
            {
                modfd(m_epollfd,m_sockfd,EPOLLIN,true);
                return false;
            }
        }
    }
    
}

//填写HTTP报文段的行连接函数
bool http_conn::add_response(const char* format,...)
{
    char* tmp = static_cast<char*>(MemPool->task(512));
    // sio++;
    // printf("%d\n", sio);
    va_list arg_list;
    va_start(arg_list,format);
    int len=vsnprintf(tmp,512,format,arg_list);
    if(len < 512)
    {
        if(!m_write_buf)
        {
            m_write_buf = tmp;
            memoryblock = 1;
        }
        else
        {
            int n = (m_write_idx - 1) / 512 + 1;
            if(m_write_idx + len <= n * 512)
            {
                strncpy(m_write_buf + m_write_idx, tmp, len);
                MemPool->push(static_cast<void*>(tmp), 512);
                // sio--;
                // printf("%d\n", sio);
            }
            else
            {
                memoryblock++;
                char* temp = static_cast<char*>(MemPool->task((n+1) * 512));
                // sio++;
                // printf("%d\n", sio);
                strncpy(temp, m_write_buf, m_write_idx);
                strncpy(temp + m_write_idx, tmp, len);
                MemPool->push(static_cast<void*>(m_write_buf), n * 512);
                MemPool->push(static_cast<void*>(tmp), 512);
                // sio-=2;
                // printf("%d\n", sio);
                m_write_buf = temp;
            }
        }
    }
    else
        return false;
    m_write_idx+=len;
    va_end(arg_list);
    return true;
}

//填写响应报文的状态行
bool http_conn::add_status_line(int status,const char* title)
{
    return add_response("%s %d %s\r\n","HTTP/1.1",status,title);
}

//填写响应报文的头部信息
bool http_conn::add_headers(int content_len)
{
    add_content_length(content_len);
    sk();
    add_linger();
    add_blank_line();
}

//填写响应报文主信息的长度
bool http_conn::add_content_length(int content_len)
{
    return add_response("Content-Length:%d\r\n",content_len);
}

//填写响应报文答复文件的类型
bool http_conn::add_content_type()
{
    return add_response("Content-Type:%s\r\n","text/html");
}

// test
bool http_conn::sk()
{
    return add_response("Location:http://www.317.fit\r\n");
}

//填写发送响应报文之后的连接状态
bool http_conn::add_linger()
{
    return add_response("Connection:%s\r\n",(m_linger==true) ? "keep-alive" : "close");
}

//填写响应报文头部的结束符
bool http_conn::add_blank_line()
{
    return add_response("%s","\r\n");
}

//填写响应报文主信息
bool http_conn::add_content(const char* content)
{
    return add_response("%s",content);
}

//根据请求报文的读取结果，作出相应的答复
bool http_conn::process_write(HTTP_CODE ret)
{
    switch (ret)
    {
        case INTERNAL_ERROR:
        {
            add_status_line(500,error_500_title);
            add_headers(strlen(error_500_form));
            if (!add_content(error_500_form))
            {
                return false;
            }
            break;
        }
        case BAD_REQUEST:
        {
            add_status_line(400,error_400_title);
            add_headers(strlen(error_400_form));
            if (!add_content(error_400_form))
            {
                return false;
            }
            break;
        }
        case NO_RESOURCE:
        {
            add_status_line(400,error_404_title);
            add_headers(strlen(error_404_form));
            if (!add_content(error_404_form))
            {
                return false;
            }
            break;
        }
        case FORBIDDEN_REQUEST:
        {
            add_status_line(403,error_403_title);
            add_headers(strlen(error_403_form));
            if (!add_content(error_403_form))
            {
                return false;
            }
            break;
        }
        case FILE_REQUEST:
        {
            add_status_line(302,"Found");
            printf("askdh\n");
            add_headers(20);
            printf("askdh\n");
            m_iv[0].iov_base=m_write_buf;
            m_iv[0].iov_len=m_write_idx;
            m_iv_count=1;
            return true;
            // add_status_line(200,ok_200_title);
            // if (te)
            // {
            //     add_headers(te->filesize);
            //     m_iv[0].iov_base=m_write_buf;
            //     m_iv[0].iov_len=m_write_idx;
            //     m_iv[1].iov_base=te->wherefile;
            //     m_iv[1].iov_len=te->filesize;
            //     m_iv_count=2;
            //     return true;
            // }
            // else
            // {
            //     const char* ok_string="<html><body></body></html>";
            //     add_headers(strlen(ok_string));
            //     if (!add_content(ok_string))
            //         return false;
            // }
        }
        default:
        {
            return false;
        }
    }
    m_iv[0].iov_base=m_write_buf;
    m_iv[0].iov_len=m_write_idx;
    m_iv_count=1;
    return true;
}

//线程被唤醒后，开始处理HTTP请求的入口函数
void http_conn::process()
{
    // struct timeval tv;
    // struct timezone tz;
    // gettimeofday(&tv,&tz);

    if(!this->read())
    {
        this->close_conn();
        return;
    }

    time_t cur=time(NULL);
    this->time_out=cur+15;

    HTTP_CODE read_ret=process_read();
    if (read_ret==NO_REQUEST)
    {
        modfd(m_epollfd,m_sockfd,EPOLLIN,true);
        return;
    }
    if (!this->process_write(read_ret))
    {
        this->close_conn();
    }
    if(!this->write())
    {
        this->close_conn();
    }
    
    // struct timeval tv1;
    // struct timezone tz1;
    // gettimeofday(&tv1,&tz1);
    // static long long text;
    // text+=(tv1.tv_sec-tv.tv_sec)*1000000+(tv1.tv_usec-tv.tv_usec);
    // static int nums;
    // printf("%ld\n",text/++nums);
    // printf("-%ld--%d\n",text,nums);
}
